﻿#include "qlyqrencode.h"

QlyQREncode::QlyQREncode()
    : m_qr(nullptr),
      m_hint(QR_MODE_8),
      m_eclevel(QR_ECLEVEL_M),
      m_version(0),
      m_casesensitive(1),
      m_background(Qt::white),
      m_foreground(Qt::black)
{
}

void QlyQREncode::setColor(QColor foreground, QColor background)
{
    m_background = background;
    m_foreground = foreground;
}

void QlyQREncode::setErrorCorrectionLevel(QRecLevel level)
{
    m_eclevel = level;
}

bool QlyQREncode::encodeString8Bit(QString str)
{
    if(m_qr != nullptr)
    {
        QRcode_free(m_qr);
    }
    m_qr = QRcode_encodeString8bit(str.toStdString().c_str(),
                             1,
                             m_eclevel);
    return (m_qr != nullptr);
}

bool QlyQREncode::encodeStringMQR8Bit(QString str)
{
    if(m_qr != nullptr)
    {
        QRcode_free(m_qr);
    }
    m_qr = QRcode_encodeString8bitMQR(str.toStdString().c_str(),
                             1,
                             m_eclevel);
    return (m_qr != nullptr);
}

QlyQREncode::~QlyQREncode()
{
    if(m_qr != nullptr)
    {
        QRcode_free(m_qr);
    }
}

int QlyQREncode::QRWidth() const
{
    return (m_qr != nullptr) ? m_qr->width : 0;
}

bool QlyQREncode::saveImage(QString fileName, int size) const
{
    QImage image = toImage(size);
    return image.save(fileName);
}

QImage QlyQREncode::toImage(int size) const
{
    if( !m_qr ) return QImage();
    if(size == 0) size = QRWidth() * 4;
    QImage image(size, size, QImage::Format_ARGB32);
    QPainter painter(&image);
    painter.setBrush(m_background);
    painter.setPen(Qt::NoPen);
    painter.drawRect(0, 0, size, size);
    painter.setBrush(m_foreground);
    renderNoBackground(painter, size, size);
    return image;
}

bool QlyQREncode::encodeString(QString str)
{
    if(m_qr != nullptr)
    {
        QRcode_free(m_qr);
    }
    m_qr = QRcode_encodeString(str.toStdString().c_str(),
                             1,
                             m_eclevel,
                             m_hint,
                             m_casesensitive);
    return (m_qr != nullptr);
}

bool QlyQREncode::encodeStringMQR(QString str)
{
    if(m_qr != nullptr)
    {
        QRcode_free(m_qr);
    }
    m_qr = QRcode_encodeStringMQR(str.toStdString().c_str(),
                             1,
                             m_eclevel,
                             m_hint,
                             m_casesensitive);
    return (m_qr != nullptr);
}

bool QlyQREncode::render(QPainter &painter, QColor background, QColor foreground, QRect rect) const
{
    if(!m_qr || m_qr->width < 1) return false;
    if(rect.isNull())
    {
        rect.setRect(0, 0, m_qr->width * 4, m_qr->width * 4);
    }
    painter.save();
    painter.setPen(Qt::NoPen);
    painter.setBrush(background);
    painter.drawRect(rect);
    painter.setBrush(foreground);
    bool ret = renderNoBackground(painter, rect);
    painter.restore();
    return ret;
}

bool QlyQREncode::renderNoBackground(QPainter &painter, QRect rect) const
{
    if(!m_qr || m_qr->width < 1) return false;
    if(rect.isNull())
    {
        rect.setRect(0, 0, m_qr->width * 4, m_qr->width * 4);
    }
    const int qr_width = m_qr->width;
    const double offset_x = rect.left();
    const double offset_y = rect.top();
    const double scale_x = static_cast<double>(rect.width()) / qr_width;
    const double scale_y = static_cast<double>(rect.height()) / qr_width;
    for( int y = 0; y < qr_width; y ++)
    {
        for(int x = 0; x < qr_width; x ++)
        {
            unsigned char b = m_qr->data[y * qr_width + x];
            if(b & 0x01)
            {
                QRectF r(offset_x + x * scale_x, offset_y + y * scale_y, scale_x, scale_y);
                painter.drawRect(r);
            }
        }
    }
    return true;
}

bool QlyQREncode::renderNoBackground(QPainter &painter, int width, int height) const
{
    QRect rect(0, 0, width, height);
    return renderNoBackground(painter, rect);
}
